<?php
date_default_timezone_set("UTC");
require_once( realpath( dirname( __FILE__ ) . '/../globals.php' ) );

require_once( 'tsConfig.class.php' );
require_once( 'tsRequest.class.php' );
require_once( 'tsSession.class.php' );

/**
 * action base class
 *
 * @author K.Tamura <tamura@terras.co.jp>
 */
abstract class tsActionBase
{

    protected $cfg = null;
    protected $req = null;

    protected $isDebug = true;

    public function execute()
    {
        // initialize
        //
        $this->prepare();

        // session
        //
        $this->initSession();

        try
        {
            // authenticate
            //
            $this->authorize();

            // initialize before main-processing
            //
            $this->actionBefore();

            // invoke action
            //
            $this->invoke();
        }
        catch ( Exception $e )
        {
            // catch exception ...
            //
            $this->error( $e );
        }

        // dispose
        //
        $this->dispose();
    }

    private static function measureProcTime()
    {
        static $stime = null;
        if( null === $stime )
        {
            $stime = get_microtime_float();
            return $stime;
        }
        else
        {
            $etime = get_microtime_float();
            return $etime - $stime;
        }
    }

    private function prepare()
    {
        // include functions ...
        //
        $dirpath = APPPATH . '/functions';
        if( true === is_dir( $dirpath ) )
        {
            if( false !== ( $dh = opendir( $dirpath ) ) )
            {
                while( $dir = readdir( $dh ) ){
                    if( ! preg_match( '#\.inc\.php$#', $dir ) ) continue;
                    require_once( $dirpath . '/' . $dir );
                }
                closedir( $dh );
            }
        }

        // parse configs ...
        //
        $this->cfg = tsConfig::getInstance( CONF_FILE );

        // parse requests ...
        //
        $this->req = tsRequest::getInstance();

        // logger file
        //
        if( true !== defined( 'LOG_FILE' ) )
        {
            $_file = $this->cfg->get( 'DEBUG', 'file' );
            if( null === $_file )
            {
                if( false !== getenv( 'LOG_FILE' ) )
                {
                    $_file = getenv( 'LOG_FILE' );
                }
                else
                {
                    $_file = 'debug.log';
                }
            }
            if( '/' != substr( $_file, 0, 1 ) )
            {
                $_file = APPPATH . '/tmp/logs/' . $_file;
            }
            if( $suffix = $this->cfg->get( 'DEBUG', 'suffix' ) )
            {
                // logfile rotate of the application side.
                $_file = $_file . '.' . date( $suffix );
            }
            define( 'LOG_FILE', $_file );
        }

        // logger level
        //
        if( true !== defined( 'LOG_LEVEL' ) )
        {
            $_level = $this->cfg->get( 'DEBUG', 'level' );
            if( null === $_level )
            {
                if( false !== getenv( 'LOG_LEVEL' ) )
                {
                    $_level = getenv( 'LOG_LEVEL' );
                }
            }
            define( 'LOG_LEVEL', $_level );
        }

        // start debugger ...
        //
        debug( '>>>>>>>>>>>>>>> START >>>>>>>>>>>>>>>', __FILE__, __LINE__, null, 'DEBUG' );

        // start the measure processing time
        //
        self::measureProcTime();
    }

    private function initSession()
    {
        if( $this->config( 'SESSION' ) )
        {
            // session start ...
            //
            $session = new tsSession(
                                    $this->config( 'SESSION', 'handler' ),
                                    $this->config( 'SESSION', 'path' )
                                    );
            $session->start();
        }
    }

    private function dispose()
    {
        // end the measure processing time
        //
        $time = self::measureProcTime();
        $msg = sprintf( '<<<<<<<<<<<<<<< Script Execution Time: %01.05f sec. <<<<<<<<<<<<<<<', $time, 'INFO' );
        if( true === $this->isDebug )
        {
           // printf( '<div style="color:blue;font-weight:bold;">%s</div>', $msg );
        }
        debug( $msg, __FILE__, __LINE__ );
    }

    private function invoke()
    {
        // find specified action
        //
        $action = null;
        $requests = $this->req->getAll();
        if( $requests )
        {
            $keys = array_keys( $requests );
            foreach( $keys as $key )
            {
                if( 'd:' === substr( $key, 0, 2 ) )
                {
                    $action = substr( $key, 2 );
                    $action = 'do' . ucfirst( strtolower( $action ) );
                    debug( '# invoke action: ' . $action, __FILE__, __LINE__, null, 'DEBUG' );
                    break;
                }
            }
        }

        // invoke main-processing
        //
        if( null !== $action && true === method_exists( $this, $action ) )
        {
            // specified action
            $res = call_user_func( array( $this, $action ) );
        }
        else
        {
            // default action
            $res = $this->action();
        }

        return $res;
    }

    protected function authorize()
    {
        $type = $this->config( 'AUTHORIZE', 'type' );
        if( null !== $type )
        {
            require_once( 'tsAuth.class.php' );
            $auth = tsAuth::factory( $type );
            if( true === is_object( $auth ) )
            {
                $auth->checkLogin();
            }
        }
    }

    abstract protected function actionBefore();
    abstract protected function action();

    protected function error( $e )
    {
        // @todo Draw the error screen & write debug log
        printf( "%s (%s) - %s - %s", $e->getMessage(), $e->getCode(), $e->getFile(), $e->getLine() );
    }

    protected function config( $group, $key = null, $default = null )
    {
        return $this->cfg->get( $group, $key, $default );
    }

    protected function get( $key, $default = null )
    {
        return $this->req->get( $key, $default );
    }

    protected function loadTemplate( $file, $dir = null )
    {
        // set directory
        //
        $mod_dir = dirname( $_SERVER['SCRIPT_FILENAME'] );
        $tpl_dir = $mod_dir . '/templates';
        $cache_dir = $tpl_dir . '/caches';
        if( null !== $dir )
        {
            $tpl_dir = $dir . '/templates';
            $cache_dir = $tpl_dir . '/caches';
        }

        // check the actual file exists
        //
        $realpath = $tpl_dir . '/' . $file;
        if( true !== is_file( $realpath ) ) die( "Template file does not exists." );

        // genarate template engine instance
        //
        require_once( 'HTML/Template/Sigma.php' );
        $tpl = new HTML_Template_Sigma( $tpl_dir, $cache_dir );
        $tpl->setOption( 'trim_on_save', false );
        $tpl->setOption( 'charset', mb_internal_encoding() );

        // load template file
        //
        $tpl->loadTemplateFile( $file );

        // set global variables
        //
        $tpl->setGlobalVariable( 'myself', $_SERVER['PHP_SELF'] );
        // server host
        $host = $this->config( 'GENERAL', 'host' );
        $tpl->setGlobalVariable( 'HOST', $host );
        // url and secure url of the website top-screen
        $basedir = $this->config( 'GENERAL', 'basedir' );
        $_uri = trim( $host . '/' . trim( $basedir, '/' ), '/' );
        $tpl->setGlobalVariable( 'TOPURI', $this->config( 'GENERAL', 'topuri', 'http://' . $_uri ) );
        $tpl->setGlobalVariable( 'TOPURI_SECURE', $this->config( 'GENERAL', 'topuri_secure', 'https://' . $_uri ) );

        // set callback functions
        //
        // @todo coming soon ...

        return $tpl;
    }

    protected function redirect( $uri )
    {
        header( 'Location: ' . $uri );
        exit;
    }

    protected function setToken( &$tpl = null )
    {
        // generate token
        //
        $token = md5( uniqid( rand(), true ) );
        if( true === is_object( $tpl ) )
        {
            $tpl->setGlobalVariable( 'token', $token );
        }
        $_SESSION['TOKEN'] = $token;

        return $token;
    }

    protected function checkToken( $token )
    {
        // check token
        //
        $bool = false;
        if( true === isset( $_SESSION['TOKEN'] ) )
        {
            if( $_SESSION['TOKEN'] === $token )
            {
                $bool = true;
            }
            unset( $_SESSION['TOKEN'] );
        }
        return $bool;
    }

}
